package futbol.tacticas.concursantes.TacticaToluca;

import java.awt.Color;
import java.awt.Point;
import java.util.Vector;

import futbol.General;
import futbol.tacticas.Comando;
import futbol.tacticas.ComandoGolpearBola;
import futbol.tacticas.ComandoIrA;
import futbol.tacticas.ComandoTiroAPuerta;
import futbol.tacticas.SituacionJugadores;
import futbol.tacticas.concursantes.Tactica;

/**
 * 
 * @author krloxz
 */
public class TacticaToluca implements Tactica {

    private int alineacion[][] = {
        {-150, 0}, //1
        {-100, 75}, //2
        {-100, -75}, //3
        {-90, 0}, //4
        {-50, 0}, //5
        {20, 100}, //6
        {90, 75}, //7
        {90, -75}, //8
        {70, -40}, //9
        {70, 40}, //10
        {60, 0} //11
    };
    private int fuerza[] = {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};

    // Nombre del equipo
    public String getNombre() {
        return "Toluca";
    }

    // Color de playera
    public Color getColor1() {
        return Color.RED;
    }

    // Color de short
    public Color getColor2() {
        return Color.BLACK;
    }

    // Color de número
    public Color getColorNumero() {
        return Color.WHITE;
    }

    // Posición x inicial de un jugador
    public int getXInicial(int n) {
        return alineacion[n][0];
    }

    // Posición y inicial de un jugador
    public int getYInicial(int n) {
        return alineacion[n][1];
    }

    // Retorna la fuerza de un jugador
    public int getFuerza(int n) {
        misVelocidades[n] = 10 - fuerza[n];
        susVelocidades[n] = 1;
        return fuerza[n];
    }

    private void setSuVelocidad(int jugador, int velocidad) {
        if (velocidad > susVelocidades[jugador]) {
            susVelocidades[jugador] = velocidad;
        }
    }

    // Variables auxiliares para la ejecución de comandos
    SituacionJugadores situacionActual = null;
    SituacionJugadores situacionAnterior = null;
    int misVelocidades[] = new int[11];
    int susVelocidades[] = new int[11];
    int velocidadBalon = 0;
    boolean huboGol = false;

    // Comandoa a ejecutar
    public Vector<Comando> getComandos(SituacionJugadores sj) {
        if (situacionAnterior == null) {
            situacionAnterior = sj;
        }
        situacionActual = sj;
        Vector<Comando> comandos = new Vector<Comando>();
        computarVelocidad();
        //Hubo gol???
        huboGol = ((situacionAnterior.getBola().getX() >= 160 || situacionAnterior.getBola().getX() <= -160) &&
                (situacionAnterior.getBola().getY() >= -30 && situacionAnterior.getBola().getY() <= 30));

        int jugadorMasCerca = getMiJugadorMasCercaBalon();
        int jugadorPase = -1;
        double distancia = this.getDistancia(situacionActual.getMisJugadores()[jugadorMasCerca],
                situacionActual.getBola());
        if (distancia < 10) {
            if (this.puedoTirarAGol(jugadorMasCerca)) {
                comandos.add(tirarAGol(jugadorMasCerca));
            } else {
                jugadorPase = getJugadorPase(jugadorMasCerca);
                comandos.add(darPase(jugadorMasCerca, jugadorPase));
            }
        } else {
            comandos.add(irA(jugadorMasCerca, situacionActual.getBola()));
        }
        moverJugadores(jugadorMasCerca, jugadorPase, comandos);
        situacionAnterior = situacionActual;
        return comandos;
    }

    private void computarVelocidad() {
        Point posicionAnterior = null;
        Point posicionActual = null;
        int velocidad;
        for (int i = 0; i < 11; i++) {
            posicionAnterior = situacionAnterior.getContrario()[i];
            posicionActual = situacionActual.getContrario()[i];
            velocidad = (int) this.getDistancia(posicionAnterior, posicionActual);
            this.setSuVelocidad(i, velocidad);
        }
    }

    private int getVelocidadBalon() {
        if (huboGol) {
            return 0;
        }
        Point posicionAnterior = situacionAnterior.getBola();
        Point posicionActual = situacionActual.getBola();
        return (int) this.getDistancia(posicionAnterior, posicionActual);
    }

    private Point getProximoBoteBalon() {
        Point punto = new Point(situacionActual.getBola());
        int vBalon = getVelocidadBalon();
        if (vBalon > 0) {
            int maxDistancia = 0;
            for (int i = vBalon; i > 14; i--) {
                maxDistancia += i;
            }
            if (maxDistancia == 0) {
                maxDistancia = vBalon;
            }
            double angulo = this.getAngulo(situacionAnterior.getBola(), situacionActual.getBola());
            int x = (int) (Math.cos(angulo) * maxDistancia);
            int y = (int) (Math.sin(angulo) * maxDistancia);
            punto.setLocation(corregirX(situacionActual.getBola().getX() + x),
                    corregirY(situacionActual.getBola().getY() + y));
        }
        return punto;
    }

    private Comando darPase(int jugadorDe, int jugadorPara) {
        return darPase(jugadorDe, situacionActual.getMisJugadores()[jugadorPara]);
    }

    private Comando darPase(int jugador, Point punto) {
        Point pJugadorDe = situacionActual.getMisJugadores()[jugador];
        Point pJugadorPara = punto;
        double dx = pJugadorPara.getX() - pJugadorDe.getX();
        double dy = pJugadorPara.getY() - pJugadorDe.getY();
        if (dx != 0 && dy != 0) {
            double distancia = Math.sqrt(dx * dx + dy * dy);
            dx = dx / distancia;
            dy = dy / distancia;
            int fCalculada = 4;
            if (distancia > 90) {
                fCalculada = 7;
            } else if (distancia > 40) {
                fCalculada = 6;
            }
            int f = Math.min(getFuerza(jugador), fCalculada);
            double d = 50d * (double) f / getFuerza(jugador);
            double dd = d, ddx = dx, ddy = dy;
            int ff;
            do {
                dx = (int) ((double) ddx * dd);
                dy = (int) ((double) ddy * dd);
                distancia = Math.sqrt(dx * dx + dy * dy);
                ff = getFuerza(jugador) * (int) distancia / 52;
                dd++;
            } while (ff < f);
            return new ComandoGolpearBola(jugador, pJugadorDe.getX() + dx, pJugadorDe.getY() + dy);
        } else {
            return new ComandoGolpearBola(jugador, pJugadorDe.getX(), pJugadorDe.getY());
        }
    }

    private double corregirX(double x) {
        double auxiliar = 0;
        if (x < -160) {
            auxiliar = x + 160;
            return -160 - auxiliar;
        }
        if (x > 160) {
            auxiliar = x - 160;
            return 160 - auxiliar;
        }
        return x;
    }

    private double corregirY(double y) {
        double auxiliar = 0;
        if (y < -120) {
            auxiliar = y + 120;
            return -120 - auxiliar;
        }
        if (y > 120) {
            auxiliar = y - 120;
            return 120 - auxiliar;
        }
        return y;
    }

    private double getDistancia(Point p1, Point p2) {
        double x1 = p1.getX();
        double y1 = p1.getY();
        double x2 = p2.getX();
        double y2 = p2.getY();
        return General.getDistancia(x1, y1, x2, y2);
    }

    private double getAngulo(Point p1, Point p2) {
        double x1 = p1.getX();
        double y1 = p1.getY();
        double x2 = p2.getX();
        double y2 = p2.getY();
        return General.getAngulo(x1, y1, x2, y2);
    }

    private boolean puedoTirarAGol(int jugador) {
        if(situacionActual.getMisJugadores()[jugador].getX()<-60||situacionActual.getMisJugadores()[jugador].getX()>50)
            return true;
        return false;
    }

    private int getMaxDistancia(int jugador) {
        int maxDistancia = 0;
        int distancia = this.getFuerza(jugador) * 3;
        if (distancia < 15) {
            maxDistancia = distancia;
        }
        for (int i = distancia; i > 14; i--) {
            maxDistancia += i;
        }
        return maxDistancia;
    }
    
    private int getJugadorPase(int jugador) {
        int maxDistancia = getMaxDistancia(jugador);
        Point miJugador = situacionActual.getMisJugadores()[jugador];
        Point pJugador = new Point();
        Vector<Integer> seleccionados = new Vector<Integer>();
        Vector<Integer> distancias = new Vector<Integer>();
        int distancia = -1;
        for (int i = 0; i < 11; i++) {
            if (i != jugador) {
                pJugador = situacionActual.getMisJugadores()[i];
                if (miJugador.getX() < pJugador.getX()) {
                    distancia = (int) this.getDistancia(miJugador, pJugador);
                    if (distancia <= maxDistancia) {
                        seleccionados.add(i);
                        distancias.add(distancia);
                    }
                }
            }
        }
        int mejorJugador = -1;
        double x = -200;
        for (int i = 0; i < seleccionados.size(); i++) {
            pJugador = situacionActual.getMisJugadores()[seleccionados.get(i)];
            if (x < pJugador.getX()) {
                mejorJugador = seleccionados.get(i);
                x = distancias.get(i);
            }
        }
        if (mejorJugador == -1) {
            mejorJugador = situacionActual.getInfoMasCercano(situacionActual.getMisJugadores(), miJugador,
                    new int[]{jugador}, false)[0];
        }
        return mejorJugador;
    }
    
    private Comando irA(int jugador, Point punto) {
        return new ComandoIrA(jugador, punto.getX(), punto.getY());
    }

    private void moverJugadores(int jugadorExcluir1, int jugadorExcluir2, Vector<Comando> comandos) {
        if(jugadorExcluir1!=0&&jugadorExcluir2!=0)
            comandos.add(cuidarPorteria());
        moverDefensas(jugadorExcluir1, jugadorExcluir2, comandos);
        for (int i = 6; i < 11; i++) {
            if(i!=jugadorExcluir1&&i!=jugadorExcluir2)
                comandos.add(new ComandoIrA(i, alineacion[i][0], alineacion[i][1]));
        }
    }
    
    private void moverDefensas(int jExcluir1, int jExcluir2, Vector<Comando> comandos) {
        int marcados[] = {-1, -1, -1, -1, -1};
        int info[] = null;
        int excluir[] = {0, -1, -1, -1, -1, -1, 6, 7, 8, 9, 10};
        int rival;            
        for (int i = 1; i < 6; i++) {
            if (i != jExcluir1 && i != jExcluir2) {
                rival = situacionActual.getInfoMasCercano(situacionActual.getContrario(),
                        new Point(-160, 0), marcados, false)[0];
                info = situacionActual.getInfoMasCercano(situacionActual.getMisJugadores(),
                        situacionActual.getContrario()[rival], excluir, false);
                comandos.add(cubrirRival(info[0], rival));
                excluir[i] = info[0];
                marcados[i - 1] = rival;
            }
        }
    }
    
    private Comando cubrirRival(int jugador, int rival) {
        if(rival>=0){
            double x = situacionActual.getBola().getX() - situacionActual.getContrario()[rival].getX();
            double y = situacionActual.getBola().getY() - situacionActual.getContrario()[rival].getY();
            double n = Math.sqrt(Math.pow(x, 2)+Math.pow(y, 2));
            double nx = situacionActual.getContrario()[rival].getX() + (x / n) * 20;
            double ny = situacionActual.getContrario()[rival].getY() + (y / n) * 20;//Siempre delante del balon en 20u
            return new ComandoIrA(jugador, (int) nx, (int) ny);//Aqui cubre
        }
        return new ComandoGolpearBola(jugador, 160, 0);
    }

    private Comando cuidarPorteria() {
        Point proximoBote = this.getProximoBoteBalon();
        double y = proximoBote.getY();
        if (y > 30) {
            y = 30;
        } else if (y < -30) {
            y = -30;
        }
        return new ComandoIrA(0, alineacion[0][0], y);
    }

    private Comando tirarAGol(int jugador) {
        return new ComandoTiroAPuerta(jugador, 0);
    }
    
    private int getMiJugadorMasCercaBalon() {
        Point punto = new Point(this.getProximoBoteBalon());
        int info[] = situacionActual.getInfoMasCercano(situacionActual.getMisJugadores(),
                punto, null, false);
        return info[0];
    }
}

